package com.sugar.follow.up.module.business.service.followuprecord;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import com.sugar.follow.up.framework.common.pojo.PageResult;
import com.sugar.follow.up.framework.common.util.object.BeanUtils;
import com.sugar.follow.up.module.business.controller.admin.followuprecord.vo.FollowUpRecordDetailRespVO;
import com.sugar.follow.up.module.business.controller.admin.followuprecord.vo.FollowUpRecordPageReqVO;
import com.sugar.follow.up.module.business.controller.admin.followuprecord.vo.FollowUpRecordRespVO;
import com.sugar.follow.up.module.business.controller.admin.followuprecord.vo.FollowUpRecordSaveReqVO;
import com.sugar.follow.up.module.business.dal.dataobject.followupquestionrecord.FollowUpQuestionRecordDO;
import com.sugar.follow.up.module.business.dal.dataobject.followuprecord.FollowUpRecordDO;
import com.sugar.follow.up.module.business.dal.dataobject.followuptemplatequestion.FollowUpTemplateQuestionDO;
import com.sugar.follow.up.module.business.dal.dataobject.questionnairetemplatequestion.dto.OptionDTO;
import com.sugar.follow.up.module.business.dal.dataobject.userpatient.UserPatientDO;
import com.sugar.follow.up.module.business.dal.mysql.followupquestionrecord.FollowUpQuestionRecordMapper;
import com.sugar.follow.up.module.business.dal.mysql.followuprecord.FollowUpRecordMapper;
import com.sugar.follow.up.module.business.dal.mysql.followuptemplatequestion.FollowUpTemplateQuestionMapper;
import com.sugar.follow.up.module.business.dal.mysql.userpatient.UserPatientMapper;
import com.sugar.follow.up.module.business.service.userpatient.UserPatientService;
import com.sugar.follow.up.module.business.util.AdminUserUtil;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.sugar.follow.up.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.sugar.follow.up.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
import static com.sugar.follow.up.module.business.enums.ErrorCodeConstants.*;

/**
 * 随访发起记录 Service 实现类
 *
 * @author Ysugar
 */
@Service
@Validated
public class FollowUpRecordServiceImpl implements FollowUpRecordService {

    @Resource
    private FollowUpRecordMapper followUpRecordMapper;
    @Resource
    private FollowUpQuestionRecordMapper questionRecordMapper;
    @Resource
    private FollowUpTemplateQuestionMapper templateQuestionMapper;
    @Resource
    private UserPatientService userPatientService;
    @Resource
    private UserPatientMapper userPatientMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createFollowUpRecord(FollowUpRecordSaveReqVO createReqVO, Long adminUserId) {
        LocalDateTime beginTime = createReqVO.getBeginTime();
        LocalDateTime endTime = createReqVO.getEndTime();

        if (endTime.isBefore(beginTime))
            throw exception(FOLLOW_UP_RECORD_DATE_ERROR);

        // 查询模板的题目列表
        List<FollowUpTemplateQuestionDO> questions = templateQuestionMapper.selectList(FollowUpTemplateQuestionDO::getTemplateId, createReqVO.getTemplateId());
        if (CollUtil.isEmpty(questions))
            throw exception(FOLLOW_UP_TEMPLATE_QUESTION_IS_EMPTY);

        // 插入
        if (!createReqVO.getType()){
            Long[] userIds = createReqVO.getUserIds();
            insertRecord(createReqVO, adminUserId, userIds[0], userIds[1], questions);
        }else {
            List<Long> patientIds = userPatientService.execGeneratorSql(createReqVO.getTags());
            if (patientIds.isEmpty())
                throw exception(USER_PATIENT_TAGS_NONE);
            for (Long patientId : patientIds) {
                UserPatientDO userPatientDO = userPatientMapper.selectById(patientId);
                if (Objects.nonNull(userPatientDO))
                    insertRecord(createReqVO, adminUserId, userPatientDO.getUserId(), patientId, questions);
            }
        }
    }

    private void insertRecord(FollowUpRecordSaveReqVO createReqVO, Long adminUserId, Long userId, Long patientId, List<FollowUpTemplateQuestionDO> questions){
        FollowUpRecordDO followUpRecord = BeanUtils.toBean(createReqVO, FollowUpRecordDO.class);
        followUpRecord.setAdminUserId(adminUserId)
                .setUserId(userId)
                .setPatientId(patientId)
                .setDurationHour(ChronoUnit.HOURS.between(createReqVO.getBeginTime(), createReqVO.getEndTime()));
        followUpRecordMapper.insert(followUpRecord);
        Long recordId = followUpRecord.getId();

        // 插入题目
        for (FollowUpTemplateQuestionDO question : questions) {
            FollowUpQuestionRecordDO questionRecordDO = new FollowUpQuestionRecordDO();
            questionRecordDO.setRecordId(recordId)
                    .setUserId(followUpRecord.getUserId())
                    .setQuestionId(question.getId())
                    .setTitle(question.getTitle())
                    .setTip(question.getTip())
                    .setType(question.getType())
                    .setOptions(question.getOptions());
            questionRecordMapper.insert(questionRecordDO);
        }
    }

    @Override
    public void updateFollowUpRecord(FollowUpRecordSaveReqVO updateReqVO) {
        // 校验存在
        validateFollowUpRecordExists(updateReqVO.getId());

        LocalDateTime beginTime = updateReqVO.getBeginTime();
        LocalDateTime endTime = updateReqVO.getEndTime();

        if (endTime.isBefore(beginTime))
            throw exception(FOLLOW_UP_RECORD_DATE_ERROR);

        // 修改不能改模板
        updateReqVO.setTemplateId(null);

        Long[] userIds = updateReqVO.getUserIds();
        // 更新
        FollowUpRecordDO updateObj = BeanUtils.toBean(updateReqVO, FollowUpRecordDO.class);
        updateObj.setUserId(userIds[0])
                .setPatientId(userIds[1])
                .setDurationHour(ChronoUnit.HOURS.between(beginTime, endTime));
        followUpRecordMapper.updateById(updateObj);
    }

    @Override
    public void deleteFollowUpRecord(Long id) {
        // 校验存在
        validateFollowUpRecordExists(id);
        // 删除
        followUpRecordMapper.deleteById(id);
    }

    @Override
        public void deleteFollowUpRecordListByIds(List<Long> ids) {
        // 删除
        followUpRecordMapper.deleteByIds(ids);
        }


    private void validateFollowUpRecordExists(Long id) {
        if (followUpRecordMapper.selectById(id) == null) {
            throw exception(FOLLOW_UP_RECORD_NOT_EXISTS);
        }
    }

    @Override
    public FollowUpRecordDetailRespVO getFollowUpRecord(Long id) {
        FollowUpRecordDetailRespVO respVO = BeanUtils.toBean(followUpRecordMapper.selectById(id), FollowUpRecordDetailRespVO.class);
        respVO.setUserIds(new Long[]{respVO.getUserId(), respVO.getPatientId()});
        return respVO;
    }

    @Override
    public PageResult<FollowUpRecordRespVO> getFollowUpRecordPage(FollowUpRecordPageReqVO pageReqVO) {
        Long doctorId = AdminUserUtil.isSuperAdmin();
        return followUpRecordMapper.selectPage(pageReqVO, doctorId);
    }

    @Override
    public void exportFollowUpRecordExcel(FollowUpRecordPageReqVO pageReqVO, HttpServletResponse response) throws IOException {
        // 自定义头部标题
        List<String> headList1 = CollUtil.newArrayList("序号", "模板名称", "就诊人姓名", "医生姓名", "随访标题", "随访开始时间", "随访结束时间", "时长", "选项信息", "", "", "", "", "");
        List<String> headList2 = CollUtil.newArrayList("", "", "", "", "", "", "", "", "题目", "题型", "提示语", "选项标题", "选项内容", "答案");

        ExcelWriter writer = ExcelUtil.getWriter(/*"E:/test/writeBeanTest.xlsx"*/);

        // 获取样式
        StyleSet style = writer.getStyleSet();
        Font headFont = writer.createFont();
        headFont.setBold(true);
        headFont.setFontHeightInPoints((short) 16);
        //重点，设置中文字体
        headFont.setFontName("楷体");
        style.setWrapText();
        // 设置头部标题字体与背景色
        style.getHeadCellStyle().setFont(headFont);
        style.getHeadCellStyle().setFillForegroundColor(IndexedColors.WHITE.getIndex());

        // 写入头部标题
        writer.writeHeadRow(headList1);
        writer.writeHeadRow(headList2);

        // 获取所有模板
        List<FollowUpRecordRespVO> records = this.getFollowUpRecordPage(pageReqVO).getList();
        int templateRowNum = 2;
        int rowNum = 2;
        int idx = 1;
        for (FollowUpRecordRespVO record : records) {
            String templateName = record.getTemplateName();
            String patientName = record.getPatientName();
            String adminUserName = record.getAdminUserName();
            String title = record.getTitle();
            String beginTime = LocalDateTimeUtil.format(record.getBeginTime(), FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
            String endTime = LocalDateTimeUtil.format(record.getEndTime(), FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);
            String durationHour = record.getDurationHour() + " 小时";

            // 根据模板获取题目
            List<FollowUpQuestionRecordDO> questions = questionRecordMapper.selectList(FollowUpQuestionRecordDO::getRecordId, record.getId());
            int size = questions.size();
            if (size == 0) {
                // 构建该行每个单元格内容
                ArrayList<String> rowPlanContents = CollUtil.newArrayList("" + idx, templateName,
                        patientName, adminUserName, title, beginTime, endTime, durationHour, "", "", "", "", "", "");
                writer.writeRow(rowPlanContents);
                rowNum += 1;
                templateRowNum += 1;
            } else {
                for (int i = 0; i < size; i++) {
                    FollowUpQuestionRecordDO question = questions.get(i);

                    // 获取题型
                    String questionType = getQuestionType(question.getType());

                    List<OptionDTO> options = question.getOptions();
                    int optionSize = Objects.nonNull(options) ? options.size() : 0;
                    if (optionSize == 0) {
                        // 构建该行每个单元格内容
                        ArrayList<String> rowPlanContents = CollUtil.newArrayList("" + idx, templateName,
                                patientName, adminUserName, title, beginTime, endTime, durationHour,
                                question.getTitle(), questionType, question.getTip(), "", "", question.getAnswer());
                        writer.writeRow(rowPlanContents);
                        optionSize = 1;
                    } else {
                        for (OptionDTO option : options) {
                            // 构建该行每个单元格内容
                            ArrayList<String> rowPlanContents = CollUtil.newArrayList("" + idx, templateName,
                                    patientName, adminUserName, title, beginTime, endTime, durationHour,
                                    question.getTitle(), questionType, question.getTip(), option.getTitle(), option.getContent(), question.getAnswer());
                            writer.writeRow(rowPlanContents);
                        }
                    }

                    int lastRow = rowNum + optionSize - 1;

                    if (lastRow > rowNum){
                        writer.merge(rowNum, lastRow, 8, 8, question.getTitle(), false);
                        writer.merge(rowNum, lastRow, 9, 9, questionType, false);
                        writer.merge(rowNum, lastRow, 10, 10, question.getTip(), false);
                        writer.merge(rowNum, lastRow, 13, 13, question.getAnswer(), false);
                    }
                    rowNum += optionSize;
                }

                int lastRow = rowNum;

                if (rowNum > templateRowNum)
                    lastRow -= 1;

                if (lastRow > templateRowNum){
                    writer.merge(templateRowNum, lastRow, 0, 0, idx, false);
                    writer.merge(templateRowNum, lastRow, 1, 1, templateName, false);
                    writer.merge(templateRowNum, lastRow, 2, 2, patientName, false);
                    writer.merge(templateRowNum, lastRow, 3, 3, adminUserName, false);
                    writer.merge(templateRowNum, lastRow, 4, 4, title, false);
                    writer.merge(templateRowNum, lastRow, 5, 5, beginTime, false);
                    writer.merge(templateRowNum, lastRow, 6, 6, endTime, false);
                    writer.merge(templateRowNum, lastRow, 7, 7, durationHour, false);
                }
                templateRowNum = rowNum;
            }

            idx++;
        }

        // 合并标题单元格
        writer.merge(0, 1, 0, 0, "序号", true);
        writer.merge(0, 1, 1, 1, "模板名称", true);
        writer.merge(0, 1, 2, 2, "就诊人姓名", true);
        writer.merge(0, 1, 3, 3, "医生姓名", true);
        writer.merge(0, 1, 4, 4, "随访标题", true);
        writer.merge(0, 1, 5, 5, "随访开始时间", true);
        writer.merge(0, 1, 6, 6, "随访结束时间", true);
        writer.merge(0, 1, 7, 7, "时长", true);
        writer.merge(0, 0, 8, 13, "选项信息", true);

        writer.setOnlyAlias(true);
        writer.autoSizeColumnAll();

        writer.setColumnWidth(0, 10);
        writer.setColumnWidth(1, 20);
        writer.setColumnWidth(2, 20);
        writer.setColumnWidth(3, 20);
        writer.setColumnWidth(4, 20);
        writer.setColumnWidth(5, 20);
        writer.setColumnWidth(6, 20);
        writer.setColumnWidth(7, 12);
        writer.setColumnWidth(8, 25);
        writer.setColumnWidth(9, 10);
        writer.setColumnWidth(10, 15);
        writer.setColumnWidth(11, 13);
        writer.setColumnWidth(12, 25);
        writer.setColumnWidth(13, 25);

        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        // test.xls是弹出下载对话框的文件名，不能为中文，中文请自行编码
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("随访记录信息.xls", "UTF-8"));
        ServletOutputStream out = response.getOutputStream();

        writer.flush(out, true);
        // 关闭writer，释放内存
        writer.close();
        // 此处记得关闭输出Servlet流
        IoUtil.close(out);
    }

    private String getQuestionType(Integer type) {
        switch (type){
            case 0:
                return "单选题";
            case 1:
                return "多选题";
            case 2:
                return "填空题";
            case 3:
                return "问答题";
            case 4:
                return "日期选择";
            default:
                return "-";
        }
    }
}